/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package main;

import java.util.Arrays;
import java.util.List;

/**
 *
 * @author FrostBite77
 */
public class Fetcher {

    private String Inst;
    private long nxtPC;
    private String opcode;
    private int lineNum;
    private int flgNext;
    private long regContent[];
    private int type;
    private String Cmd;
    private int regRS;
    private int regRT;
    private int regRD;
    private int Imm;
    /* changes here ---*/
    private String[] opcodeString;
    private String[] rsString;
    private String[] rtString;
    private String[] rdString;
    private String[] tempString;
    private String[] funcString;
    private String[] labels = new String[50];
    private int length;
    private int jmpto;
    private int ptr;

    /* up to here ---*/
    public Fetcher() {
    }

    int search(String instarray[]) {

        length = instarray.length;
        int flag = 1;

        for (int x = 0; x < instarray.length; x++) {
            
            labels[x] = "wala";

            if (instarray[x].contains(":")) {
                int v = 0;
                String word = "";
                while (instarray[x].charAt(v) != ':') {
                    word += instarray[x].charAt(v);
                    v++;
                }
                for(int a=0;a<x;a++){
                    if(labels[a].equals(word)){
                        flag--;
                        break;
                    }
                }
                if(flag==1)
                    labels[x] = word;
            } 
            }
        return flag;
        }
    

    void Parse() {

        String instruction = getInst();
        String tokens[];
        String RType[] = {"DADD", "DSUB", "OR", "XOR", "SLT"};
        String IType[] = {"LD", "SD"};
        String IType2 = "BNEZ";
        String IType3 = "DADDI";
        String JType = "J";
        String regName[] = {"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31"};





        List RTypeList = Arrays.asList(RType);
        List ITypeList = Arrays.asList(IType);
        List regNameList = Arrays.asList(regName);





        instruction = instruction.replace("(", " "); //converts the parentheses to space for easier tokenizing
        instruction = instruction.replace(")", "");
        instruction = instruction.replace("#", "");
        tokens = instruction.split(":\\s|\\s|\\s,|,\\s|\\t,|,\\t|\\t|:\\t"); //tokenizes the whole line of instruction by replacing the commas with spaces then setting the spaces as delimiters



        if (!RTypeList.contains(tokens[0].toUpperCase()) && !ITypeList.contains(tokens[0].toUpperCase()) && !IType2.equals(tokens[0].toUpperCase()) && !IType3.equals(tokens[0].toUpperCase()) && !JType.equals(tokens[0].toUpperCase())) { //check if line has a possible label
            if (!tokens[0].equals(";")) { //check if line starts with a ;
                System.out.println("has a label: " + tokens[0]);
                if (tokens.length == 5) {
                    System.out.println("Tokens: " + tokens[1] + " " + tokens[2] + " " + tokens[3] + " " + tokens[4]);

                    if (RTypeList.contains(tokens[1].toUpperCase()) && regNameList.contains(tokens[2].toUpperCase()) && regNameList.contains(tokens[3].toUpperCase()) && regNameList.contains(tokens[4].toUpperCase())) {
                        setType(1);
                        tokens[1] = tokens[1].toUpperCase();
                        tokens[2] = tokens[2].toUpperCase();
                        tokens[3] = tokens[3].toUpperCase();
                        tokens[4] = tokens[4].toUpperCase();
                        System.out.println("R-Type");
                        setCmd(tokens[1]);
                        setRegRD(regNameList.indexOf(tokens[2]));
                        setRegRS(regNameList.indexOf(tokens[3]));
                        setRegRT(regNameList.indexOf(tokens[4]));
                        Convert();


                        setFlgNext(1); //allows to read another line
                    } else if (ITypeList.contains(tokens[1].toUpperCase()) && !tokens[1].toUpperCase().equals("DADDI") && regNameList.contains(tokens[2].toUpperCase()) && Integer.parseInt(tokens[3], 16) <= Integer.parseInt("FFFF", 16) && regNameList.contains(tokens[4].toUpperCase())) {
                        setType(2);
                        tokens[1] = tokens[1].toUpperCase();
                        tokens[2] = tokens[2].toUpperCase();
                        tokens[4] = tokens[4].toUpperCase();
                        System.out.println("I-Type");
                        setCmd(tokens[1]);
                        setImm(Integer.parseInt(tokens[3], 16));
                        setRegRS(regNameList.indexOf(tokens[2]));
                        setRegRT(regNameList.indexOf(tokens[4]));

                        Convert();


                        setFlgNext(1); //allows to read another line
                    } else if (IType3.equals(tokens[1].toUpperCase()) && regNameList.contains(tokens[2].toUpperCase()) && regNameList.contains(tokens[3].toUpperCase()) && Integer.parseInt(tokens[4], 16) <= Integer.parseInt("FFFF", 16)) {
                        setType(2);
                        tokens[1] = tokens[1].toUpperCase();
                        tokens[2] = tokens[2].toUpperCase();
                        tokens[3] = tokens[3].toUpperCase();
                        setImm(Integer.parseInt(tokens[4], 16));
                        setRegRS(regNameList.indexOf(tokens[2]));
                        setRegRT(regNameList.indexOf(tokens[3]));
                        setCmd(tokens[1]);
                        System.out.println("I-Type");


                        setFlgNext(1); //allows to read another line
                        Convert();


                    } else {
                        main.MainWindow.jLabelError.setText("The instruction: " + instruction + " at line " + getLineNum() + " is invalid");
                        setFlgNext(0);
                    }
                } else if (tokens.length == 4 && IType2.equals(tokens[1].toUpperCase()) && regNameList.contains(tokens[2].toUpperCase()) && Integer.parseInt(tokens[3], 16) <= Integer.parseInt("FFFF", 16)) {
                    setType(2);
                    tokens[1] = tokens[1].toUpperCase();
                    tokens[2] = tokens[2].toUpperCase();
                    //get the imm for the label (offset)
                    //set imm

                    setFlgNext(1); //allows to read another line
                    Convert();

                } else if (tokens.length == 3 && tokens[1].toUpperCase().equals(JType)) {

                    setType(3);
                    tokens[1] = tokens[1].toUpperCase();
                    setCmd(tokens[1]);
                    System.out.println("J-Type");
                    setFlgNext(1); //allows to read another line
                    Convert();

                } else {
                    main.MainWindow.jLabelError.setText("The instruction: " + instruction + " at line " + getLineNum() + " is invalid");
                    setFlgNext(0);
                }
            } else {
                main.MainWindow.jLabelError.setText("An illegal start of expression: " + instruction + " at line " + getLineNum() + ".");
                setFlgNext(0);
            }

        } else { //if line is without label
            if (!tokens[0].equals(";")) {
                if (tokens.length == 4) {
                    System.out.println("Tokens: " + tokens[0] + " " + tokens[1] + " " + tokens[2] + " " + tokens[3]);
                    if (RTypeList.contains(tokens[0].toUpperCase()) && regNameList.contains(tokens[1].toUpperCase()) && regNameList.contains(tokens[2].toUpperCase()) && regNameList.contains(tokens[3].toUpperCase())) {
                        setType(1);
                        tokens[0] = tokens[0].toUpperCase();
                        tokens[1] = tokens[1].toUpperCase();
                        tokens[2] = tokens[2].toUpperCase();
                        tokens[3] = tokens[3].toUpperCase();
                        System.out.println("R-Type");
                        setCmd(tokens[0]);
                        setRegRD(regNameList.indexOf(tokens[1]));
                        setRegRS(regNameList.indexOf(tokens[2]));
                        setRegRT(regNameList.indexOf(tokens[3]));
                        Convert();

                        setFlgNext(1); //allows to read another line
                    } else if (ITypeList.contains(tokens[0].toUpperCase()) && regNameList.contains(tokens[1].toUpperCase()) && Integer.parseInt(tokens[2], 16) <= Integer.parseInt("FFFF", 16) && regNameList.contains(tokens[3].toUpperCase())) {
                        setType(2);
                        tokens[0] = tokens[0].toUpperCase();
                        tokens[1] = tokens[1].toUpperCase();
                        tokens[3] = tokens[3].toUpperCase();
                        System.out.println("I-Type");
                        setCmd(tokens[0]);
                        setImm(Integer.parseInt(tokens[2], 16));
                        setRegRT(regNameList.indexOf(tokens[1]));
                        setRegRS(regNameList.indexOf(tokens[3]));
                        Convert();


                        setFlgNext(1); //allows to read another line
                    } else if (IType3.equals(tokens[0].toUpperCase()) && regNameList.contains(tokens[1].toUpperCase()) && regNameList.contains(tokens[2].toUpperCase()) && Integer.parseInt(tokens[3], 16) <= Integer.parseInt("FFFF", 16)) {
                        setType(2);
                        tokens[0] = tokens[0].toUpperCase();
                        tokens[1] = tokens[1].toUpperCase();
                        tokens[2] = tokens[2].toUpperCase();
                        System.out.println("I-Type");
                        setImm(Integer.parseInt(tokens[3], 16));
                        setRegRT(regNameList.indexOf(tokens[1]));
                        setRegRS(regNameList.indexOf(tokens[2]));
                        setCmd(tokens[0]);

                        setFlgNext(1); //allows to read another line
                        Convert();


                    } else {
                        main.MainWindow.jLabelError.setText("The instruction: " + instruction + "; at line " + getLineNum() + " is invalid");
                        setFlgNext(0);
                    }
                } else if (tokens.length == 3 && IType2.equals(tokens[0].toUpperCase()) && regNameList.contains(tokens[1].toUpperCase())) {
                    System.out.println("Tokens: " + tokens[0] + " " + tokens[1] + " " + tokens[2]);
                    setType(2);
                    tokens[0] = tokens[0].toUpperCase();
                    tokens[1] = tokens[1].toUpperCase();
                    setRegRS(regNameList.indexOf(tokens[1]));
                    setRegRT(0);
                    setCmd(tokens[0]);
                    System.out.println("I-Type");


                    int x = 0;
                    while (x<length) {  //get the imm for the label (offset)
                        if (labels[x].equals(tokens[2])) {
                            break;
                        } 
                            x++;
                        
                    }
                    
                    setImm(x - (getLineNum()+1));
                    setCmd(tokens[0]);

                    jmpto = x; //set imm


                    setFlgNext(1); //allows to read another line
                    if(x<length)
                    Convert();
                    else
                        main.MainWindow.jLabelError.setText("Label at line " + getLineNum() + " not found");

                } else if (tokens.length == 2 && tokens[0].toUpperCase().equals(JType)) {

                    setType(3);
                    tokens[0] = tokens[0].toUpperCase();
                    System.out.println("J-Type");
                    int x = 0;
                    while (x<length) {  //get the imm for the label (offset)
                        if (labels[x].equals(tokens[1])) {
                            break;
                        } 
                            x++;
                        
                    }
                    
                    setImm(x * 4);
                    setFlgNext(1); //allows to read another line
                    setCmd(tokens[0]);
                    Convert();

                } else {
                    main.MainWindow.jLabelError.setText("The instruction: " + instruction + " at line " + getLineNum() + " is invalid");
                    setFlgNext(0);
                }
            } else {
                main.MainWindow.jLabelError.setText("An illegal start of expression: " + instruction + " at line " + getLineNum() + ".");
                setFlgNext(0);
            }
        }
    }

    void Convert() {
        String[] temp = new String[32];
        Arrays.fill(temp, "0");
        String[] IType;
        String[] JType = {"0", "0", "0", "0", "1", "0"};

        int func;


        String[] RegOp = new String[5];
        String[] ImmOp = new String[16];
        System.out.println("\n\nConverting...");

        RegOp = String.format("%5s", Integer.toBinaryString(getRegRS())).replace(' ', '0').split("(?!^)"); //convert RS
        System.arraycopy(RegOp, 0, temp, 6, 5);



        switch (getType()) {

            case 1:

                RegOp = String.format("%5s", Integer.toBinaryString(getRegRT())).replace(' ', '0').split("(?!^)"); //convert RT
                System.arraycopy(RegOp, 0, temp, 11, 5);
                RegOp = String.format("%5s", Integer.toBinaryString(getRegRD())).replace(' ', '0').split("(?!^)"); //convert RD
                System.arraycopy(RegOp, 0, temp, 16, 5);


                switch (getCmd()) {
                    case "DADD":
                        func = 44;
                        RegOp = String.format("%5s", Integer.toBinaryString(func)).replace(' ', '0').split("(?!^)"); //convert RT
                        System.arraycopy(RegOp, 0, temp, 26, 5);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));

                        break;

                    case "DSUB":
                        func = 46;
                        RegOp = String.format("%5s", Integer.toBinaryString(func)).replace(' ', '0').split("(?!^)"); //convert RT
                        System.arraycopy(RegOp, 0, temp, 26, 5);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;

                    case "OR":
                        func = 37;
                        RegOp = String.format("%5s", Integer.toBinaryString(func)).replace(' ', '0').split("(?!^)"); //convert RT
                        System.arraycopy(RegOp, 0, temp, 26, 5);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;

                    case "XOR":
                        func = 38;
                        RegOp = String.format("%5s", Integer.toBinaryString(func)).replace(' ', '0').split("(?!^)"); //convert RT
                        System.arraycopy(RegOp, 0, temp, 26, 5);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;

                    case "SLT":
                        func = 42;
                        RegOp = String.format("%5s", Integer.toBinaryString(func)).replace(' ', '0').split("(?!^)"); //convert RT
                        System.arraycopy(RegOp, 0, temp, 26, 5);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;
                }
                break;

            case 2:

                RegOp = String.format("%5s", Integer.toBinaryString(getRegRT())).replace(' ', '0').split("(?!^)"); //convert RT
                System.arraycopy(RegOp, 0, temp, 11, 5);
                ImmOp = String.format("%16s", Integer.toBinaryString(getImm())).replace(' ', '0').split("(?!^)");
                System.out.println(ImmOp.length);
                System.arraycopy(ImmOp, 16, temp, 16, 16);
                switch (getCmd()) {

                    case "BNEZ":
                        IType = String.format("%6s", Integer.toBinaryString(5)).replace(' ', '0').split("(?!^)");
                        System.arraycopy(IType, 0, temp, 0, 6);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));

                        break;

                    case "DADDI":
                        IType = String.format("%6s", Integer.toBinaryString(24)).replace(' ', '0').split("(?!^)");
                        System.arraycopy(IType, 0, temp, 0, 6);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;

                    case "LD":
                        IType = String.format("%6s", Integer.toBinaryString(55)).replace(' ', '0').split("(?!^)");
                        System.arraycopy(IType, 0, temp, 0, 6);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;

                    case "SD":
                        IType = String.format("%6s", Integer.toBinaryString(63)).replace(' ', '0').split("(?!^)");
                        System.arraycopy(IType, 0, temp, 0, 6);
                        System.out.println("Opcode:");
                        System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                        break;

                }
                break;
            case 3:
                System.arraycopy(JType, 0, temp, 0, 6);
                ImmOp = String.format("%26s", Integer.toBinaryString(getImm())).replace(' ', '0').split("(?!^)");
                System.arraycopy(ImmOp, 0, temp, 6, 26);
                System.out.println("Opcode:");
                System.out.println(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));
                setOpcode(Arrays.toString(temp).replaceAll(",|\\[|\\]|\\s", ""));

        }




    }

    /**
     * @return the nxtPC
     */
    public long getNxtPC() {
        return nxtPC;
    }

    /**
     * @param nxtPC the nxtPC to set
     */
    public void setNxtPC(long nxtPC) {
        this.nxtPC = nxtPC;
    }

    /**
     * @return the lineNum
     */
    public int getLineNum() {
        return lineNum;
    }
    /* changes here ---*/

    public void splitOpcode(String[] opcode, String type) {

        if (type.equalsIgnoreCase("rtype")) {

            System.arraycopy(opcode, 0, opcodeString, 0, 6);
            System.arraycopy(opcode, 6, rsString, 0, 5);
            System.arraycopy(opcode, 11, rtString, 0, 5);
            System.arraycopy(opcode, 16, rdString, 0, 5);
            System.arraycopy(opcode, 21, opcodeString, 0, 5);
            System.arraycopy(opcode, 26, funcString, 0, 6);
        } else if (type.equalsIgnoreCase("itype")) {

            System.arraycopy(opcode, 0, opcodeString, 0, 6);
            System.arraycopy(opcode, 6, rsString, 0, 5);
            System.arraycopy(opcode, 11, rtString, 0, 5);
            System.arraycopy(opcode, 16, rdString, 0, 16);
        } else if (type.equalsIgnoreCase("jtype")) {

            System.arraycopy(opcode, 0, opcodeString, 0, 6);
            System.arraycopy(opcode, 6, rsString, 0, 26);
        }

    }

    /* up to here ---*/
    /**
     * @param lineNum the lineNum to set
     */
    public void setLineNum(int lineNum) {
        this.lineNum = lineNum;
    }

    /**
     * @return the Inst
     */
    public String getInst() {
        return Inst;
    }

    /**
     * @param Inst the Inst to set
     */
    public void setInst(String Inst) {
        this.Inst = Inst;
    }

    /**
     * @return the flgNext
     */
    public int getFlgNext() {
        return flgNext;
    }

    /**
     * @param flgNext the flgNext to set
     */
    public void setFlgNext(int flgNext) {
        this.flgNext = flgNext;
    }

    public long[] getRegContent() {
        return regContent;
    }

    public void setRegContent(long[] RegContent) {
        this.regContent = RegContent;
    }

    /**
     * @return the Cmd
     */
    public String getCmd() {
        return Cmd;
    }

    /**
     * @param Cmd the Cmd to set
     */
    public void setCmd(String Cmd) {
        this.Cmd = Cmd;
    }

    /**
     * @return the CmdType
     */
    public int getType() {
        return type;
    }

    /**
     * @param CmdType the CmdType to set
     */
    public void setType(int type) {
        this.type = type;
    }

    /**
     * @return the opcode
     */
    /**
     * @return the regRS
     */
    public int getRegRS() {
        return regRS;
    }

    /**
     * @param regRS the regRS to set
     */
    public void setRegRS(int regRS) {
        this.regRS = regRS;
    }

    /**
     * @return the regRT
     */
    public int getRegRT() {
        return regRT;
    }

    /**
     * @param regRT the regRT to set
     */
    public void setRegRT(int regRT) {
        this.regRT = regRT;
    }

    /**
     * @return the regRD
     */
    public int getRegRD() {
        return regRD;
    }

    /**
     * @param regRD the regRD to set
     */
    public void setRegRD(int regRD) {
        this.regRD = regRD;
    }

    /**
     * @return the opcode
     */
    public String getOpcode() {
        return opcode;
    }

    /**
     * @param opcode the opcode to set
     */
    public void setOpcode(String opcode) {
        this.opcode = opcode;
    }

    /**
     * @return the Imm
     */
    public int getImm() {
        return Imm;
    }

    /**
     * @param Imm the Imm to set
     */
    public void setImm(int Imm) {
        this.Imm = Imm;
    }

    /**
     * @set instruction pointer
     */
    public void setPtr(int ptr) {
        this.ptr = ptr;
    }

    /**
     * @get the jump location
     */
    public int getJmp() {
        int x = jmpto;
        jmpto = 0;
        return x;
    }

    /**
     * @get da lenth
     */
    public void setLength(int length) {
        this.length = length;
    }
}
